<?php
/**
 * Albireo Kernel
 *
 * @copyright  Copyright (c) 2010 Albireo Solutions
 * @package    Kernel
 */

namespace KernelModule\AclModule;

use KernelModule\UsersModule\RolesModel;

use Albireo\Forms\AlbireoForm;
use Nette\Forms\Form;
use Nette\Application\AppForm;

use \dibi;
use \DibiException;
use \InvalidStateException;

/**
 * Permission presenter
 *
 */
class PermissionsPresenter extends BasePresenter {

    /** @var AclManagment */
    private $aclManager;

    /**
     * Lazy getter for AclManagement
     * @return AclManagement
     */
    private function getAclManager() {
        if ($this->aclManager === NULL) {
            $this->aclManager = new AclManagement();
        }
        return $this->aclManager;
    }

    public function renderDefault($search) {
        $this->search = $search;

        $this->template->title = _("Permissions Management");
        $this->template->search = $search;

        $this->bringPermissions($search);
    }

    public function handleDefault($search) {
        $this->bringPermissions($search);
        $this->invalidateControl("list");
    }

    private function bringPermissions($search) {
        $form = $this->getComponent('search');
        $form->setDefaults(array("permission" => $this->search));

        $paginator = $this->getComponent("paginator")->getPaginator();

        $perDataSource = $this->getAclManager()->getSearchDataSource("permissions", $this->search);

        $paginator->itemCount = $perDataSource->count();
        $perDataSource->applyLimit($paginator->itemsPerPage, $paginator->offset);


        $result = $perDataSource->getResult();
        $rows = $result->fetchAll();

        $acl = array();
        foreach($rows as $p) {
            $permission = new Acl();
            $resource = new AclResource();
            $role = new AclRole();
            $privilege = new AclPrivilege();

            $resource->setName($p["resource"]);
            $privilege->setName($p["privilege"]);
            $role->setName($p["role"]);

            $permission->setId($p["id"]);
            $permission->setResource($resource);
            $permission->setRole($role);
            $permission->setPrivilege($privilege);
            $permission->setAllowed($p["allowed"]);
            $acl[] = $permission;
        }
        $this->template->acl = $acl;
    }


    public function actionAdd($id) {
        $this->template->title = _("Add New Permission");
        $this->template->form = $this["add"];
    }

    protected function createComponentAdd() {
        $form = new AlbireoForm();

        $access = array(1 => _('Allow'), 0 => _('Deny'));

        $mroles = new RolesModel();
        $roles = $mroles->getTreeValues();

        //gets the resources and privileges as two arrays, those are members of $resPrivData - array[2]
        foreach (array("resources", "privileges") as $class) {
            $resPrivData[$class] = $this->getAclManager()->getDataSource($class)->orderBy("name")->fetchPairs("id", "name");
        }

        $form->addMultiSelect('role_id', _('Role'), $roles, 15)
                ->addRule(Form::FILLED, _('You have to fill roles.'));
        $form->addMultiSelect('resource_id', _('Resource'), $resPrivData["resources"], 15)
                ->addRule(Form::FILLED, _('You have to fill resources.'));
        $form->addMultiSelect('privilege_id', _('Privilege'), $resPrivData["privileges"], 15)
                ->addRule(Form::FILLED, _('You have to fill privileges.'));
        $form->addRadioList('allowed', _('Access'), $access)
                ->addRule(Form::FILLED, _('You have to fill access.'));

        $form->addSubmit('add', _('Add'));
        $this->addCancelButton($form);
        $form->onSubmit[] = array($this, 'addSubmitted');

        return $form;
    }

    /**
     * When the "add" form is submitted, the new permissions are created
     * in the database.
     *
     * @param AlbireoForm $form
     */
    public function addSubmitted(AlbireoForm $form) { // Permission form submitted
        $values = $form->getValues();
        $allowed = $values["allowed"];
        try {
            foreach ($values['privilege_id'] as $privilegeId) {
                foreach ($values['resource_id'] as $resourceId) {
                    foreach ($values['role_id'] as $roleId) {
                        $acl = $this->getAclManager()->getAclFromIds($roleId, $resourceId, $privilegeId, $allowed);
                        $this->getAclManager()->addAcl($acl);
                    }
                }
            }
            $this->flashMessage(_('Permission was successfully assigned.'), 'ok');
            $this->redirect('default');
        } catch (DibiException $e) {
            $form->addError(_('An error occured while assigning the permission.'), 'error');
        }
    }
    
    public function actionEdit($id) {
        $this->template->title = _("Edit Permission");
        $this->template->form = $this["edit"];

        $permission = $this->getAclManager()->getPermissionById($id);
        
        if ($permission == null) throw new \InvalidStateException();
        
        $defaults = array(
            "id" => $id,
            "privilege_id" => $permission->getPrivilege()->getId(),
            "resource_id" => $permission->getResource()->getId(),
            "role_id" => $permission->getRole()->getId(),
            "allowed" => $permission->getAllowed() ? 1 : 0,
        );
        
        $form = $this->getComponent('edit');
        $form->setDefaults($defaults);
    }
    

    protected function createComponentEdit() {
        $form = new AlbireoForm();

        $access = array(1 => _('Allow'), 0 => _('Deny'));

        //TODO move to the AclManagement
        $mroles = new RolesModel();
        $roles = $mroles->getTreeValues();

        //gets the resources and privileges as two arrays, those are members of $resPrivData - array[2]
        foreach (array("resources", "privileges") as $class) {
            $resPrivData[$class] = $this->getAclManager()->getDataSource($class)->orderBy("name")->fetchPairs("id", "name");
        }

        $form->addSelect('role_id', _('Role'), $roles, 15)
                ->addRule(Form::FILLED, _('You have to fill roles.'));
        $form->addSelect('resource_id', _('Resource'), $resPrivData["resources"], 15)
                ->addRule(Form::FILLED, _('You have to fill resources.'));
        $form->addSelect('privilege_id', _('Privilege'), $resPrivData["privileges"], 15)
                ->addRule(Form::FILLED, _('You have to fill privileges.'));
        $form->addRadioList('allowed', _('Access'), $access)
                ->addRule(Form::FILLED, _('You have to fill access.'));
        $form->addHidden("id"); //why do i need to create it manually?

        $form->addSubmit('edit', _('Edit'));
        $this->addCancelButton($form);
        $form->onSubmit[] = array($this, 'editSubmitted');

        return $form;
    }


    public function editSubmitted(AlbireoForm $form) {
        $values = $form->getValues();
        try {
            $acl = $this->getAclManager()->getAclFromIds($values['role_id'], $values['resource_id'], $values['privilege_id'], $values["allowed"]);
            $acl->setId($values["id"]);
            if ($this->getAclManager()->updateAcl($acl)) {
                $this->flashMessage(_('Permission was successfully assigned.'), 'ok');
                $this->redirect('default');
            } else {
                $form->addError(_("The wanted combination has been already assigned."), 'error');
            }
        } catch (DibiException $e) {
            //$form->addError(_('An error occured while assigning the permission.'), 'error');
            throw $e;
        }
    }


    public function actionDelete($id) {
        $permissionsDataSource = $this->getAclManager()->getPermissionsDataSource()->where("[id]=$id");
        $result = $permissionsDataSource->getResult();
        $row = $result->fetch();
        
        //TODO asi by se to melo udelat objektove, tedy pouzit neco jako AclManagement->getAclByNevimco(...)
        
        if (count($row) == 0) {
            $this->flashMessage(_("The resource doesn't exist."), "error");
            $this->redirect('default');
        }

        $this->template->acl = $row;
        
        $this->template->title = _("Delete Permission");
        $this["delete"]->setDefaults(array("id" => $row["id"]));
    }

    public function deleteOnFormSubmitted(AlbireoForm $form){
        if ($form['delete']->isSubmittedBy()) {
            $values = $form->getValues();
            $deletedPermission = $this->getAclManager()->getPermissionById($values["id"]);
            if ($this->getAclManager()->deleteFromAcl($deletedPermission)) {
                $this->flashMessage(_('The permission has been removed from ACL.'), 'ok');
            } else $this->flashMessage(_("The permission has not been removed from ACL, an error occured."), "error");
        }
        $this->redirect("default");
    }


    protected function createComponentSearch($name) {
        return $this->createSearchForm($name, _("permission"));
    }

    public function searchSubmitted(AppForm $form) {
        $values = $form->getValues();
        $this->search = $values["searchinput"];
        $this->redirect("default");
    }
}